package com.hsoft.zhxy.common.exception;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.log4j.Log4j2;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.servlet.http.HttpServletRequest;
import javax.validation.ConstraintViolationException;

/**
 * 
 * All rights Reserved, Designed By 哈尔滨工业大学软件工程股份有限公司
 * 
 * @Title: GlobalExceptionHandler 全局异常处理
 * @Description: 全局异常处理 如果使用@RestControllerAdvice 注解 则会将返回的数据类型转换成JSON格式
 * @author: menglingwei
 * @date: 2020年5月16日 下午1:06:53
 */
@Log4j2
@RestControllerAdvice
public class GlobalExceptionHandler {

    /**
     * 处理自定义的业务异常
     * 
     * @param req
     * @param e
     * @return
     */
    @ExceptionHandler(value = BizException.class)
    public ExcpResultBody bizExceptionHandler(HttpServletRequest req, BizException e) {
        if(log.isErrorEnabled()) log.error("发生自定义业务异常！原因是：{}", e.getErrorMsg());
        return ExcpResultBody.error(e.getErrorCode(), e.getErrorMsg());
    }

    /**
     * 处理空指针的异常
     * 
     * @param req
     * @param e
     * @return
     */
    @ExceptionHandler(value = NullPointerException.class)
    public ExcpResultBody exceptionHandler(HttpServletRequest req, NullPointerException e) {
        if(log.isErrorEnabled()) log.error("发生空指针异常！原因是:", e.getMessage());
        return ExcpResultBody.error(ExcpCodeInfoEnum.INTERNAL_SERVER_ERROR, e.getMessage());
    }

    /**
     * 处理数据校验异常
     * @param req
     * @param e
     * @return
     */
    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    public ExcpResultBody exceptionHandler(HttpServletRequest req, MethodArgumentNotValidException e) {
        JSONArray jsonArr = new JSONArray();
        for (FieldError error : e.getBindingResult().getFieldErrors()) {
            JSONObject jsonObj = new JSONObject();
            jsonObj.put("field", error.getField());
            jsonObj.put("message", error.getDefaultMessage());
            jsonArr.add(jsonObj);
        }
        if(log.isDebugEnabled()) log.debug("数据校验未通过！原因是:" + jsonArr.toJSONString());
        return ExcpResultBody.error(ExcpCodeInfoEnum.USER_ERROR_A0151, jsonArr);
    }

    /**
     * 处理数据校验异常
     * @param req
     * @param e
     * @return
     */
    @ExceptionHandler(value = BindException.class)
    public ExcpResultBody exceptionHandler(HttpServletRequest req, BindException e) {
        JSONArray jsonArr = new JSONArray();
        for (FieldError error : e.getBindingResult().getFieldErrors()) {
            JSONObject jsonObj = new JSONObject();
            jsonObj.put("field", error.getField());
            jsonObj.put("message", error.getDefaultMessage());
            jsonArr.add(jsonObj);
        }
        if(log.isDebugEnabled()) log.debug("数据校验未通过！原因是:" + jsonArr.toJSONString());
        return ExcpResultBody.error(ExcpCodeInfoEnum.USER_ERROR_A0151, jsonArr);
    }

    /**
     * 处理其他异常
     * @param req
     * @param e
     * @return
     */
    @ExceptionHandler(value = IllegalStateException.class)
    public ExcpResultBody exceptionHandler(HttpServletRequest req, IllegalStateException e) {
        if(log.isErrorEnabled()) log.error("服务器端异常！原因是:", e.getMessage());
        return ExcpResultBody.error(ExcpCodeInfoEnum.INTERNAL_SERVER_ERROR, e.getMessage());
    }

    /**
     * 处理其他异常
     * @param req
     * @param e
     * @return
     */
    @ExceptionHandler(value = Exception.class)
    public ExcpResultBody exceptionHandler(HttpServletRequest req, Exception e) {

        // ConstraintViolationException 该数据校验异常需要进行特殊处理
        if(e instanceof ConstraintViolationException){
            String message = e.getMessage();
            if(log.isDebugEnabled()) log.debug("数据校验未通过！原因是:" + message );
            return ExcpResultBody.error(ExcpCodeInfoEnum.USER_ERROR_A0151, message);
        }

        if(log.isErrorEnabled()) log.error("服务器端异常！原因是:", e);
        return ExcpResultBody.error(ExcpCodeInfoEnum.INTERNAL_SERVER_ERROR, e);
    }

}